package com.xpj.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;

@Slf4j
public class CacheAnnotationProcessor {


    private static final SpelExpressionParser SPEL_EXPRESSION_PARSER = new SpelExpressionParser();

    /**
     * 生成缓存键
     */
    public static String generateCacheKey(ProceedingJoinPoint joinPoint, Annotation annotation) {
        String keyPrefix = (String)AnnotationUtils.getValue(annotation, "keyPrefix");
        String keySpEL = (String)AnnotationUtils.getValue(annotation, "keySpEL");
        int keyParamIndex = (int)AnnotationUtils.getValue(annotation, "keyParamIndex");

        // 优先使用SpEL表达式
        if (!keySpEL.isEmpty()) {
            try {
                // 创建表达式上下文
                EvaluationContext context = new MethodBasedEvaluationContext(
                        joinPoint.getTarget(),
                        getMethod(joinPoint),
                        joinPoint.getArgs(),
                        new DefaultParameterNameDiscoverer());

                // 解析表达式
                Object keySuffix = SPEL_EXPRESSION_PARSER.parseExpression(keySpEL).getValue(context);
                return keySuffix != null ? keyPrefix + keySuffix : null;
            } catch (Exception e) {
                log.error("解析SpEL表达式失败: {}", keySpEL, e);
                return null;
            }
        }

        // 使用参数索引
        Object[] args = joinPoint.getArgs();
        if (keyParamIndex >= 0 && keyParamIndex < args.length) {
            Object keyParam = args[keyParamIndex];
            return keyParam != null ? keyPrefix + keyParam : null;
        }
        return null;
    }

    /**
     * 获取连接点对应的方法
     */
    private static Method getMethod(ProceedingJoinPoint joinPoint) {
        try {
            String methodName = joinPoint.getSignature().getName();
            Class<?>[] parameterTypes = Arrays.stream(joinPoint.getArgs())
                    .map(Object::getClass)
                    .toArray(Class[]::new);
            return joinPoint.getTarget().getClass().getMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e) {
            log.error("获取方法信息失败", e);
            return null;
        }
    }
}
